/**
 * @Copyright:Copyright (c) 2007 - 2023
 * 
 */
package com.tengtong.duang.app.query.core;

import java.util.LinkedList;

import com.tengtong.commons.collections.ListUtils;
import com.tengtong.commons.lang.ArrayUtils;
import com.tengtong.commons.lang.ExceptionUtils;
import com.tengtong.commons.lang.StringBuilderX;
import com.tengtong.commons.lang.StringUtils;
import com.tengtong.duang.app.query.core.ConditionExpressBuilder.SimpleExpressBuilder;
import com.tengtong.duang.app.query.core.QueryConstants.BooleanOp;


/**
 * 转换成 sql 的条件表达式
 *
 * @author lin_jinming
 * @since: v1.0
 */
public class ToSqlExpress {

    /**
     * 将中间数据结构转为 sql 语句的 where 条件表达式
     *
     * @param datas
     * @return
     */
    public static String toWhere(LinkedList<Object> datas) {
        LinkedList<Object> results = ListUtils.newLinkedList();
        
        if(ListUtils.notEmpty(datas)) {
            int index = datas.size() - 1;
            while(index >= 0) {
                Object data = datas.get(index--);
                if(BooleanOp.check(data)) { 
                    // 操作符，压入栈
                    results.push(data);
                } else {
                    // 当前 data 是数据，看看栈有没有数据
                    if(results.size() > 0) {
                        // 按道理，此时栈顶应该是操作
                        Object op = results.pop();
                        if(BooleanOp.check(op)) {
                            // 单目运算
                            if(op == BooleanOp.NOT) {
                                var sb = parseNotExpress(data);
                                
                                // 如果栈顶不是操作符，则压操作符入栈
                                if(results.size() > 0 && !BooleanOp.check(results.peek())) {
                                    results.push(BooleanOp.AND);
                                }
                                
                                results.push(sb);
                            } else {
                                // 双目运算
                                // 从栈拿下一个数据，然后进行处理
                                Object firstData = results.pop();
                                
                                String nextExpress = null;
                                // 对 data 进行处理 （第一个数据）
                                if(data instanceof LinkedList list) {
                                    // 一组表达式
                                    nextExpress = toWhere(list);
                                } else {                        
                                    if(data instanceof StringBuilder sb) {
                                        nextExpress = sb.toString();
                                    } else {
                                        nextExpress = parseExpress((FieldValueExpress)data);
                                    }
                                }
                                // 与第二个数据进行运算处理
                                StringBuilder tmpSB = new StringBuilder();
                                if(firstData instanceof FieldValueExpress kv) {
                                    tmpSB.append("(").append(parseExpress(kv)).append(")");
                                    tmpSB.append(BooleanOp.ofObject(op).name());
                                    tmpSB.append("(").append(nextExpress).append(")");                                

                                    results.push(tmpSB);
                                } else {
                                    if(firstData instanceof StringBuilder b) {
                                        tmpSB.append("(").append(b).append(")")
                                             .append(BooleanOp.ofObject(op).name())
                                             .append("(").append(nextExpress).append(")");
                                        
                                        results.push(tmpSB);
                                    } else {
                                        if(firstData instanceof LinkedList list) {
                                            var firstExpress = toWhere(list);
                                            tmpSB.append("(").append(firstExpress).append(")")
                                                 .append(BooleanOp.ofObject(op).name())
                                                 .append("(").append(nextExpress).append(")");
                                            
                                            results.push(tmpSB);
                                        } else {
                                           throw ExceptionUtils.ofRuntime("语法错误|不认识的数据：%s", data);
                                        }
                                    }
                                }                                
                            }
                        } else {
                            // 不是操作符，可能是个错误
                            throw ExpressParseException.of("语法错误|错误的结果：%s", op);
                        }
                    } else {
                        // 没数据，就将数据压栈
                        results.push(data);
                    }
                }
            }
            
            if(results.size() == 1) {
                var data = results.pop();
                if(data instanceof StringBuilder sb) {
                    return sb.toString();
                }
                
                if(data instanceof LinkedList list) {
                    return toWhere(list);
                }
                
                throw ExpressParseException.of("语法错误|错误的结果：%s", data);
            }
            
            if(results.size() > 0) {
                return toWhere(results);
            }
        }
        return null;        
    }
    
    /**
     * 处理 Not 单目表达式
     *
     * @param express
     * @return
     */
    private static StringBuilder parseNotExpress(Object express) {
        // 是一个表达式
        StringBuilderX tmpSb = StringBuilderX.of();
        if(express instanceof FieldValueExpress kv) {
            return tmpSb.append("!(")
                        .append(parseExpress(kv)).append(")")
                        .toStringBuilder();
        }
        
        if(express instanceof LinkedList list) {
            var firstExpress = toWhere(list);
            tmpSb.append("!(").append(firstExpress).append(")");
            return tmpSb.toStringBuilder();
        }
        
        if(express instanceof StringBuilder s) {
            return tmpSb.append("!(").append(s).append(")").toStringBuilder();
        }
        
        if(express.getClass().isArray()) {
            tmpSb.append("(");
            ArrayUtils.eachArray(express, (o)->{
                if(tmpSb.length() > 1) {
                    tmpSb.append(" AND ");
                }
                tmpSb.append("!")
                     .append(StringUtils.asString(o).trim());
            });
            return tmpSb.append(")").toStringBuilder();
        }
        
        throw ExceptionUtils.ofRuntime("语法错误|不认识的数据：%s", express);
    }
    
    // 将 kv 变成关系表达式
    private static String parseExpress(FieldValueExpress kv) {
        ConditionExpressBuilder builder = new SimpleExpressBuilder();
        
        return builder.build(kv);
    }    
}
